package com.quectel.core.module.ai.service.impl.mongo;


import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.constant.core.ResourceGroupCodeConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.constants.MongoCollectionConstants;
import com.quectel.core.module.MongoAuthComponent;
import com.quectel.core.module.ai.dto.mongo.MongoAiEventRecordDto;
import com.quectel.core.module.ai.entity.mongo.MongoAiEventRecordModel;
import com.quectel.core.module.ai.service.mongo.MongoAiEventRecordService;
import com.quectel.core.module.device.dto.DeviceCategoryDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.service.DeviceCategoryService;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.DateUtils;
import com.quectel.util.common.Request;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mongo.MongodbUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 * @date 2021-11-22 11:47:45
 */
@DubboService
public class MongoAiEventRecordServiceImpl implements MongoAiEventRecordService {

    private static final Logger LOGGER = LoggerFactory.getLogger(MongoAiEventRecordServiceImpl.class);

    @Autowired
    private MongoAuthComponent mongoAuthComponent;
    @Autowired
    private DeviceCategoryService deviceCategoryService;
    @Autowired
    private DeviceTypeService deviceTypeService;
    @Autowired
    private VillageService villageService;

    private Criteria sqlWhere(Map<String, Object> params) {
        Request request = Request.configParams(params);

        Criteria authByAllQuery = mongoAuthComponent.buildAuthByAllQuery(params
                , LambdaUtil.getFieldName(MongoAiEventRecordModel::getTenantId)
                , LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceCategoryId)
                , LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceTypeId)
                , LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceId)
                , LambdaUtil.getFieldName(MongoAiEventRecordModel::getVillageId)
                , LambdaUtil.getFieldName(MongoAiEventRecordModel::getBuildingId)
        );
        Criteria filterResourceGroupCode = new Criteria();
        if (StringUtils.isNotBlank(request.getString(ResourceGroupCodeConstants.AUTH_RESOURCE_GROUP_CODE_FLAG))) {
            filterResourceGroupCode.andOperator(mongoAuthComponent.buildFilterByResourceGroupQuery(params
                    , LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceCategoryId)
                    , LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceTypeId)
            ));
        }

        Criteria otherFieldQuery = new Criteria();

        Date startTime = request.getDate(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtils.FormatType.COMMON.getType());
        Date endTime = request.getDate(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(), DateUtils.FormatType.COMMON.getType());
        if (startTime != null && endTime != null) {
            otherFieldQuery.and(LambdaUtil.getFieldName(MongoAiEventRecordModel::getRecordTime)).gte(startTime).lte(endTime);
        }

        Byte eventType = request.getByte(LambdaUtil.getFieldName(MongoAiEventRecordModel::getEventType));
        if (eventType != null) {
            otherFieldQuery.and(LambdaUtil.getFieldName(MongoAiEventRecordModel::getEventType)).is(eventType);
        }

        Long deviceId = request.getLong(LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceId));
        if (deviceId != null) {
            otherFieldQuery.and(LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceId)).is(deviceId);
        }

        Long villageId = request.getLong(LambdaUtil.getFieldName(MongoAiEventRecordModel::getVillageId));
        if (villageId != null) {
            otherFieldQuery.and(LambdaUtil.getFieldName(MongoAiEventRecordModel::getVillageId)).is(villageId);
        }

        String deviceName = request.getString(LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceName));
        if (StringUtils.isNotBlank(deviceName)) {
            otherFieldQuery.and(LambdaUtil.getFieldName(MongoAiEventRecordModel::getDeviceName)).regex(".*?\\" + deviceName + ".*");
        }

        Byte[] eventTypes = request.getArray("eventTypes", Byte.class);
        if (eventTypes != null && eventTypes.length > 0) {
            otherFieldQuery.and(LambdaUtil.getFieldName(MongoAiEventRecordModel::getEventType)).in(
                    Arrays.stream(eventTypes).toArray()
            );
        }
        return new Criteria().andOperator(authByAllQuery, filterResourceGroupCode, otherFieldQuery);
    }

    @Override
    public MongoAiEventRecordDto selectById(Long id) {
        MongoAiEventRecordModel one = MongodbUtils.findOne(id, MongoCollectionConstants.AI_EVENT_RECORD, MongoAiEventRecordModel.class);
        return CopyUtils.copyObj(one, MongoAiEventRecordDto.class);
    }

    @Override
    public List<MongoAiEventRecordDto> queryList(Map<String, Object> params) {
        Request request = Request.configParams(params);
        return
                MongodbUtils.page(
                        new Query(sqlWhere(params)),
                        request.getPageNo() - 1,
                        request.getPageSize(),
                        Sort.by(Sort.Direction.DESC, SystemConstants.MONGO_ENTITY_ID_FLAG),
                        MongoAiEventRecordModel.class,
                        MongoCollectionConstants.AI_EVENT_RECORD
                ).stream().map(model -> {
                    MongoAiEventRecordDto dto = CopyUtils.copyObj(model, MongoAiEventRecordDto.class);
                    DeviceCategoryDto deviceCategoryDto = deviceCategoryService.selectCacheById(dto.getDeviceCategoryId());
                    dto.setDeviceCategoryDto(deviceCategoryDto);

                    DeviceTypeDto deviceTypeDto = deviceTypeService.selectCacheById(dto.getDeviceTypeId());
                    dto.setDeviceTypeDto(deviceTypeDto);

                    VillageDto villageDto = villageService.selectCacheById(dto.getVillageId());
                    dto.setVillageDto(villageDto);
                    return dto;
                }).collect(Collectors.toList());
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return (int) MongodbUtils.count(new Query(sqlWhere(params)), MongoCollectionConstants.AI_EVENT_RECORD);
    }

    @Override
    public Long save(MongoAiEventRecordDto dto) {
        MongoAiEventRecordModel entity = CopyUtils.copyObj(dto, MongoAiEventRecordModel.class);
        entity.setId(Snowflake.nextId());
        MongodbUtils.insert(entity, MongoCollectionConstants.AI_EVENT_RECORD);
        return entity.getId();
    }


    @Override
    public void deleteById(Long id) {
        MongodbUtils.delete(id, MongoCollectionConstants.AI_EVENT_RECORD);
    }

    @Override
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            MongodbUtils.delete(id, MongoCollectionConstants.AI_EVENT_RECORD);
        }
    }
}
